unit uFrmPort;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls;

type
  pFunParameter = ^FunParameter;

  FunParameter = record
    i: Integer;
  end;

type
  TFrmPort = class(TForm)
    lbledtBasePort: TLabeledEdit;
    lbledtAltPort: TLabeledEdit;
    chkSlave: TCheckBox;
    lvRes: TListView;
    btnSetPortOK: TButton;
    procedure ScanATA;
    procedure btnSetPortOKClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    // procedure CreateParams(var Params: TCreateParams); override;
    procedure chkSlaveClick(Sender: TObject);
    procedure lvResClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure lvResDblClick(Sender: TObject);
  private
    bIsActive: Boolean;
    pFunParam: FunParameter;
  public
  end;

var
  FrmPort: TFrmPort;

function GetID: Integer;

implementation

uses
  uTaskFile, uCommon, uThreadManager, StorageDevice;

{$R *.dfm}

procedure TFrmPort.ScanATA;
var
  Item: TListItem;
  i: Integer;
  strBasePort, strAltPort: string;
  ATAPortList: TList;
begin
  ATAPortList := TList.Create;
  try
    if not EnumStorIOPort(ATAPortList) then
      Exit;
    lvRes.Clear;
    for i := 0 to ATAPortList.Count - 1 do
    begin
      strBasePort := Format('0x%.04X', [PIO_Port(ATAPortList.Items[i])^.BasePort]);
      strAltPort := Format('0x%.04X', [PIO_Port(ATAPortList.Items[i])^.AltPort]);
      with lvRes do
      begin
        Item := Items.Add;
        Item.Caption := IntToStr(i);
        Item.SubItems.Add(strBasePort);
        Item.SubItems.Add(strAltPort);
        Item.SubItems.Add('');
      end;
    end;
  finally
    ATAPortList.Free;
  end;
end;

procedure TFrmPort.btnSetPortOKClick(Sender: TObject);
begin
  FrmPort.Close;
end;

procedure TFrmPort.chkSlaveClick(Sender: TObject);
begin
  if ThreadManager.IsActive then
    Exit;
  if chkSlave.Checked then
    Slave := 1
  else
    Slave := 0;
  TaskFile.DeviceSelect(Slave);
end;

{
  procedure TFrmPort.CreateParams(var Params: TCreateParams);
  begin
  inherited;
  Params.WndParent := 0;
  end;
}

procedure TFrmPort.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if bIsActive then
  begin
    Action := caHide;
    repeat
      Application.ProcessMessages;
    until (bIsActive = False);
    Action := caFree;
  end
  else
    Action := caFree;
end;

procedure TFrmPort.FormDestroy(Sender: TObject);
begin
  if (Length(lbledtBasePort.Text) = 6) and (Length(lbledtAltPort.Text) = 6) then
  begin
    strBasePort := lbledtBasePort.Text;
    strAltPort := lbledtAltPort.Text;
    BasePort := StrToInt(strBasePort.Replace('0x', '$'));
    AltPort := StrToInt(strAltPort.Replace('0x', '$'));
    SaveIniFile;
    TaskFile.SetPortAddr(BasePort, AltPort, Slave);
  end;
  FrmPort := nil;
end;

procedure TFrmPort.FormShow(Sender: TObject);
begin
  lbledtBasePort.Text := strBasePort;
  lbledtAltPort.Text := strAltPort;
  chkSlave.Checked := (Slave = 1);
  ScanATA;
end;

function GetIdentify(var bBuffer: TBytes): Boolean;
begin
  Result := False;
  if not TaskFile.Identify then
    Exit;
  Result := TaskFile.ReadDataToBuffer(bBuffer);
end;

function IDENT(bBuffer: TBytes): string;
var
  i, j: Integer;
  temp, output, model, fwrev, serial: string;
begin
  output := '';
  temp := '';
  j := 0;
  for i := 1 to 20 do
  begin
    temp := temp + Char(bBuffer[54 + j + 1]);
    temp := temp + Char(bBuffer[54 + j]);
    j := j + 2;
  end;
  model := TrimRight(temp);
  model := TrimLeft(model);
  temp := 'MDL: ' + model;
  output := output + temp;
  temp := '';
  j := 0;
  for i := 1 to 4 do
  begin
    temp := temp + Char(bBuffer[46 + j + 1]);
    temp := temp + Char(bBuffer[46 + j]);
    j := j + 2;
  end;
  fwrev := TrimRight(temp);
  temp := ' FW: ' + fwrev;
  output := output + temp;
  temp := '';
  j := 0;
  for i := 1 to 10 do
  begin
    temp := temp + Char(bBuffer[20 + j + 1]);
    temp := temp + Char(bBuffer[20 + j]);
    j := j + 2;
  end;
  serial := TrimRight(temp);
  serial := TrimLeft(serial);
  temp := ' SN: ' + serial;
  output := output + temp;
  Result := output;
end;

function ID(): string;
var
  bBuffer: TBytes;
  output: string;
begin
  Result := '';
  if TaskFile.ERR then
    Exit;
  SetLength(bBuffer, 512);
  try
    if GetIdentify(bBuffer) then
      output := IDENT(bBuffer);
  finally
    SetLength(bBuffer, 0);
  end;
  Result := output;
end;

function GetID: Integer;
var
  i: Integer;
begin
  i := FrmPort.pFunParam.i;
  FrmPort.lvRes.Items[i].SubItems[2] := ID;
  Result := i;
end;

procedure TFrmPort.lvResClick(Sender: TObject);
var
  i: Integer;
begin
  i := lvRes.ItemIndex;
  if i = -1 then
    Exit;
  if ThreadManager.IsActive then
    Exit;
  try
    lbledtBasePort.Text := lvRes.Selected.SubItems.Strings[0];
    lbledtAltPort.Text := lvRes.Selected.SubItems.Strings[1];
    strBasePort := lbledtBasePort.Text;
    strAltPort := lbledtAltPort.Text;
    BasePort := StrToInt(strBasePort.Replace('0x', '$'));
    AltPort := StrToInt(strAltPort.Replace('0x', '$'));
    TaskFile.SetPortAddr(BasePort, AltPort, Slave);
    if lvRes.Items[i].SubItems[2] <> '' then
      Exit;
    pFunParam.i := i;
    bIsActive := True;
    ThreadManager.Run(@GetID);
  finally
    bIsActive := False;
  end;
end;

procedure TFrmPort.lvResDblClick(Sender: TObject);
var
  i: Integer;
begin
  i := lvRes.ItemIndex;
  if i = -1 then
    Exit;
  if ThreadManager.IsActive then
    Exit;
  try
    lbledtBasePort.Text := lvRes.Selected.SubItems.Strings[0];
    lbledtAltPort.Text := lvRes.Selected.SubItems.Strings[1];
    strBasePort := lbledtBasePort.Text;
    strAltPort := lbledtAltPort.Text;
    BasePort := StrToInt(strBasePort.Replace('0x', '$'));
    AltPort := StrToInt(strAltPort.Replace('0x', '$'));
    TaskFile.SetPortAddr(BasePort, AltPort, Slave);
    pFunParam.i := i;
    bIsActive := True;
    ThreadManager.Run(@GetID);
  finally
    bIsActive := False;
  end;
end;

end.

